package com.gc.cscott;

import com.gc.cscott.cli.Command;
import com.gc.cscott.cli.CommandsEnum;
import com.gc.cscott.cli.UnknownCommand;
import com.gc.cscott.ioc.FasModule;
import com.gc.cscott.util.CscottFomatter;
import com.gc.cscott.util.CscottUtil;
import com.google.common.collect.ImmutableList;
import com.google.inject.Guice;
import com.google.inject.Injector;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;

/**
 *
 * @author root
 */
public class Main {
    private static final Logger log = Logger.getLogger(Main.class.getSimpleName());
    /**
     * @param args the command line arguments.
     */
    public static void main(String[] args) {
        try {
            configureLogging();
            log.log(Level.INFO, "STARTED {0}", CscottUtil.currentTimeString());
            Injector injector = Guice.createInjector(
                    new FasModule());

            if (args.length > 0) {
                //print help if aquired.
                if ("help".equals(args[0])==true){
                    printHelp(injector, args.length>1?args[1]:null);
                    return;
                }
                //process the rest.
                List<String> pendingArgumentsList = ImmutableList.of(args);
                while(pendingArgumentsList.isEmpty()==false){
                    final String commandName = pendingArgumentsList.get(0);
                    pendingArgumentsList = ImmutableList.copyOf(pendingArgumentsList.subList(1, pendingArgumentsList.size()));
                    Class<? extends Command> commandType = findCommand(commandName);
                    Command command = injector.getInstance(commandType);
                    final String rule = StringUtils.repeat("-", 29);
                    log.info(String.format("%s %20s %s",rule, commandType.getSimpleName(), rule));
                    System.out.flush();
                    System.err.flush();
                    pendingArgumentsList = command.perform(pendingArgumentsList);
                    System.out.flush();
                    System.err.flush();
                }
            } else {
                printHelp(injector, null);
            }
            log.log(Level.INFO, "COMPLETED {0}", CscottUtil.currentTimeString());
        } catch (Throwable th) {
            log.severe(ExceptionUtils.getFullStackTrace(th));
        }
    }

    private static void configureLogging() throws SecurityException, IOException {
        Logger global = Logger.getLogger("");
        global.setLevel(Level.ALL);
        for (Handler defaultHandler : global.getHandlers()) {
            global.removeHandler(defaultHandler);
        }
        ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setFormatter(new CscottFomatter());

        File logsDir = new File("logs");
        if (logsDir.isDirectory()==false){
            if (logsDir.mkdirs()==false){
                new Error("Can no create directory to store log files: "+logsDir.getAbsolutePath()).printStackTrace();
            }
        }
        FileHandler fileHandler = new FileHandler("logs/cscott-"+CscottUtil.currentTimeString()+"-all.log", true);
        fileHandler.setFormatter(new CscottFomatter());
        fileHandler.setLevel(Level.ALL);

        FileHandler severeHandler = new FileHandler("logs/cscott-"+CscottUtil.currentTimeString()+"-severe.log", true);
        severeHandler.setFormatter(new CscottFomatter());
        severeHandler.setLevel(Level.SEVERE);
        global.addHandler(consoleHandler);
        global.addHandler(fileHandler);
        global.addHandler(severeHandler);
    }

    public static void printHelp(Injector injector, String filter) {
        final PrintStream output = System.err;
        output.println("cscott - Computer Sciencs Contest Testing Tool.");
        output.println("As it is runned with no agruments help is printed.");
        String separator = StringUtils.repeat("-", 80);
        output.println(separator);
        output.println("List of commands:");
        boolean someHelpPrinted = false;
        for (CommandsEnum commandEnum : CommandsEnum.values()) {
            if (filter!=null){
                if (filter.equals(commandEnum.getCommandShortName())==false
                        && filter.equals(commandEnum.getCommandName())==false){
                    continue;
                }
            }
            Command command = injector.getInstance(commandEnum.getCommandType());
            List<String> commandHelp = command.listHelp();
            if (commandHelp != null) {
                String helpPrefix = "  " + commandEnum.getCommandName() + " (" + commandEnum.getCommandShortName() + ") - ";

                output.println(helpPrefix + commandHelp.get(0));
                for (String helpLine : commandHelp.subList(1, commandHelp.size())) {
                    output.println(StringUtils.repeat(" ", 16) + helpLine);
                }
            }
            someHelpPrinted=true;
        }
        if (!someHelpPrinted){
            output.println("No commands mathes: "+filter);
        }
        output.println(separator);
        output.println("Use 'cscott help <comamand-name>' to get help by custom command.");
        output.println(separator);
        output.println("Application is developed to support informatics contests in VSU,");
        output.println("Voronezh, 2010, Dmitry S. Mamonov, Chair of MO EVM.");
    }

    private static Class<? extends Command> findCommand(String commandName) {
        for (CommandsEnum commandEnum : CommandsEnum.values()) {
            if (commandEnum.getCommandName().equals(commandName)
                    || commandEnum.getCommandShortName().equals(commandName)) {
                return commandEnum.getCommandType();
            }
        }
        return UnknownCommand.class;
    }
}
